// 常规的 {} 字面量语法允许创建一个对象。创建多个类似的对象，可以使用 new 操作符来实现。
// 这是构造器的主要目的 —— 实现可重用的对象创建代码。

// *****************************************************************************************************

// 构造函数，构造函数就是常规函数，但是有两个约定：1. 函数名必须以大写字母开头；2. 它们只能由 new 操作符来执行。
function User(name) {
	// 被 new 操作符执行时的步骤：
	// 1. this = {} 一个新的空对象被创建，并分配给 this（隐式创建）。
	// 2. 函数体执行。
	// 3. 默认返回 this 对象（隐式返回）。
	this.name = name
	this.isAdmin = false
}

let user1 = new User('John')
let user2 = new User('Jane')

console.log(user1.name, user1.isAdmin) // John false
console.log(user2.name, user2.isAdmin) // Jane false

// *****************************************************************************************************

// 【立即调用的构造函数，无法重复调用，用于创建复杂的对象】

let u = new (function () {
	this.name = 'Ben'
	this.isAdmin = false
})()

console.log(u.name, u.isAdmin) // Ben false

// *****************************************************************************************************

// 【构造器模式测试：new.target】通过 new.target 属性，可以判断当前函数是否由 new 操作符执行。
function Person() {
	console.log(new.target)
}

Person() // undefined
new Person() // Person {}

// * 应用场景（但不推荐，还是推荐通过 new 操作符来调用更为直观）
function Dog(name) {
	// 判断是否通过 new 操作符调用
	if (!new.target) {
		return new Dog(name)
	}

	this.name = name
}

let d = Dog('Rufus')
console.log(d) // Dog { name: 'Rufus' }

// *****************************************************************************************************

// 【构造器的 return】一般不会这么写，通常没有 return 语句。

// 如果构造器存在 return 执行一下规则：
// 1. 如果 return 返回的是一个对象，则返回该对象，而不是 this 对象。
// 2. 如果 return 返回的是一个原始类型的值，则忽略该值，返回 this 对象。

// 例1：
function Fn() {
	this.name = 'Fn'
	return { name: '为而不恃' }
}

console.log(new Fn().name) // 为而不恃

// 例2：
function Fn2() {
	this.name = 'Fn2'
	return
}

console.log(new Fn2().name) // Fn

// *****************************************************************************************************
